import base64
import datetime
import hashlib
import hmac
import json
import ssl
import websocket
import _thread as thread
from datetime import datetime
from time import mktime
from urllib.parse import urlparse
from urllib.parse import urlencode
from wsgiref.handlers import format_date_time
from PIL import Image
answer = ""
def resize_images(images):
    # 获取所有图像的尺寸
    sizes = [Image.open(img).size for img in images]
    min_width, min_height = min(sizes)
    
    # 调整所有图像的大小为最小尺寸
    resized_images = [Image.open(img).resize((min_width, min_height)) for img in images]
    
    return resized_images

def combine_images_vertically(images, output_path):
    # 调整所有图像的大小为最小尺寸
    resized_images = resize_images(images)
    
    # 打开所有图像并获取宽度和高度
    widths, heights = zip(*(i.size for i in resized_images))
    
    # 计算输出图像的宽度和高度
    total_width = max(widths)
    total_height = sum(heights)
    
    # 创建一张空白的大图像
    combined_image = Image.new('RGB', (total_width, total_height))
    
    # 将每张小图像粘贴到大图像中
    y_offset = 0
    for img in resized_images:
        combined_image.paste(img, (0, y_offset))
        y_offset += img.size[1]  # 更新y偏移量
    
    # 保存拼接后的图像
    combined_image.save(output_path)
    
    # 关闭所有已打开的图像
    for img in resized_images:
        img.close()


appid = "d3fb4c44"
api_secret = "OGNjNmY5N2M0NDhmZDQ4YzIxOTc2ZjUz"
api_key = "85311692ef36b5181251a367868fe9fe"
imageunderstanding_url = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image"


class Ws_Param(object):
    # 初始化
    def __init__(self, APPID, APIKey, APISecret, imageunderstanding_url):
        self.APPID = APPID
        self.APIKey = APIKey
        self.APISecret = APISecret
        self.host = urlparse(imageunderstanding_url).netloc
        self.path = urlparse(imageunderstanding_url).path
        self.ImageUnderstanding_url = imageunderstanding_url

    # 生成url
    def create_url(self):
        # 生成RFC1123格式的时间戳
        now = datetime.now()
        date = format_date_time(mktime(now.timetuple()))

        # 拼接字符串
        signature_origin = "host: " + self.host + "\n"
        signature_origin += "date: " + date + "\n"
        signature_origin += "GET " + self.path + " HTTP/1.1"

        # 进行hmac-sha256进行加密
        signature_sha = hmac.new(
            self.APISecret.encode("utf-8"),
            signature_origin.encode("utf-8"),
            digestmod=hashlib.sha256,
        ).digest()

        signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding="utf-8")

        authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'

        authorization = base64.b64encode(authorization_origin.encode("utf-8")).decode(
            encoding="utf-8"
        )

        # 将请求的鉴权参数组合为字典
        v = {"authorization": authorization, "date": date, "host": self.host}
        # 拼接鉴权参数，生成url
        url = self.ImageUnderstanding_url + "?" + urlencode(v)
        # print(url)
        # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释，比对相同参数时生成的url与自己代码生成的url是否一致
        return url
# 收到websocket错误的处理
def on_error(ws, error):
    print("### error:", error)
# 收到websocket关闭的处理
def on_close(ws, one, two):
    print("### ws-closed")
# 收到websocket连接建立的处理
def on_open(ws):
    thread.start_new_thread(run, (ws,))
def run(ws, *args):
    data = json.dumps(gen_params(appid=ws.appid, question=ws.question))
    ws.send(data)
# 收到websocket消息的处理
def on_message(ws, message):
    # print(message)
    data = json.loads(message)
    code = data["header"]["code"]
    if code != 0:
        ws.close()
        return f"请求错误: {code}, {data}"
    else:
        choices = data["payload"]["choices"]
        status = choices["status"]
        content = choices["text"][0]["content"]
        print(content, end="")
    
        global answer
        answer += content
        # print(1)
        with open("/home/xinan-works/Combine_chat_res.txt",'w') as file:
            file.write(answer)
        if status == 2:
            ws.close()
def gen_params(appid, question):

    data = {
        "header": {"app_id": appid},
        "parameter": {
            "chat": {
                "domain": "image",
                "temperature": 0.5,
                "top_k": 4,
                "max_tokens": 2028,
                "auditing": "default",
            }
        },
        "payload": {"message": {"text": question}},
    }

    return data
def main(appid, api_key, api_secret, imageunderstanding_url, question):

    wsParam = Ws_Param(appid, api_key, api_secret, imageunderstanding_url)
    websocket.enableTrace(False)
    wsUrl = wsParam.create_url()
    ws = websocket.WebSocketApp(
        wsUrl,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
        on_open=on_open,
    )
    ws.appid = appid
    # ws.imagedata = imagedata
    ws.question = question
    ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
def getText(role, imagepath, content):
    imagedata = open(imagepath, "rb").read()

    text = [
        {
            "role": role,
            "content": str(base64.b64encode(imagedata), "utf-8"),
            "content_type": "image",
        },
        {
            "role": role,
            "content": content,
            "content_type": "text",
        },
    ]

    return text
def getlength(text):
    length = 0
    for content in text:
        temp = content["content"]
        leng = len(temp)
        length += leng
    return length
def checklen(text):
    while getlength(text[1:]) > 8000:
        del text[1]
        print("d", end="")
    return text


def Combine_Chat():
    image_paths = {
        "/home/xinan-works/res/forgery_result.jpg":'在SIFT特征点提取基础上，将局部相同的SIFT特征点簇做映射后，点簇间对应点连线',
        "/home/xinan-works/res/ela/difference_scaled.png":'原图和90%有损压缩后的图像，经过做差提取的差异图像',
        "/home/xinan-works/res/noise_res.jpg":'原图分块后提取块内方差，形成灰度图',
        "/home/xinan-works/res/trufor/_local.png":'经过噪声指纹提取的图像(RdBu_r类型)'
    }
    with open("/home/xinan-works/truefor_num.txt",'r') as file:
        textinfo=str(file.read())
    #print(list(image_paths.keys()))
    #print(list(image_paths.values()))
    output_file = "combined_image.jpg"
    combine_images_vertically(image_paths.keys(), output_file)

    answer=""
    question=checklen
    knowledge="""作为专家你知道很多知识：
    图像篡改大致可以分为复制-粘贴、覆盖、深度伪造等几种类型
[复制-粘贴：将图像的局部，复制粘贴到图像的另一个位置；往往会导致图像中有两块或多块高度相似的区域
覆盖：图像的某一区域被其他像素或者图像覆盖，往往会导致覆盖区域和原图其他区域的统计数据有所差异
深度伪造：利用对抗生成网络、人工智能、深度学习、大模型等技术，对图像进行局部替换、微调等篡改]

此外，对于图像各种变换后的结果，你也有深刻的认识，和伪造性评判依据
[噪声方差提取结果：将图像分块进行噪声方差提取后聚类分析，如果聚类中心点数值差大于阈值，则存在“覆盖篡改”的可能性较高。
SIFT特征点提取匹配结果：提取SIFT图像特征点，对于相似的特征点簇内的特征点进行一一映射；如果图像出现了连线，则至少说明存在相似区域，“复制-粘贴”类图像篡改的可能性较高
误差水平分析结果：原图和有损压缩后的图像进行差异提取与增强。如果图像中出现少量差异特征亮点，属于正常范围；如果图像中出现大量差异特征亮点，则说明“像素变换相关的篡改”的可能性较高。
噪声指纹提取结果：噪声指纹差异区域以RdBu_r类型表征，颜色越浓表征差异越强，如果图像是经过伪造或篡改的，则极有可能是被篡改区域。噪声指纹提取结果附带一个归一化的篡改置信度值，数值越大，越有可能是经过伪造的：0.7以上几乎可以确定是伪造的，0.4~0.7有一定的可能是伪造的，0.4以下伪造的可能性较低]
"""
    # 背景设定
    raw = f"你是一个图像领域的专家，对于各类图像篡改或者伪造方式了如指掌。对于以下知识你更是非常了解：【{knowledge}】。而你现在需要判断一张图像是否是被篡改或伪造的。我已经帮你提前对原图像做了处理，并把各个结果整合为一个图像：\n"
    for i in range(len(image_paths.values())):
        raw += f"自上而下第{i}张，是{list(image_paths.values())[i]}\n"
    # 文本参数信息
    raw += f"除了上述图像，还有一些参数信息：【{textinfo}】,如果{textinfo}，0.7以上几乎可以确定是伪造的，0.4~0.7有一定的可能是伪造的，0.4以下伪造的可能性较低\n"
    # 回答格式限定
    answerformat="现在，根据上述信息，你已经可以对原图是否进行过篡改或伪造这一问题进行回答了。注意！作为一个专家，你的回答有着严格的格式要求，具体如下，填空，其他信息不要出现："
    #answerformat+="①该图像的内容是：_____（填写你所理解到的内容）；合理性：_____（填 合理/存在合理性/有些不合理/不合理 的其中一个\n"
    answerformat+=f"①依据上述信息，该图像是经过篡改或伪造的可能性：_____(填 几乎不可能/较低/较高/几乎一定 的其中一个，记得参考置信度{textinfo})\n"
    answerformat+="②如果是篡改或伪造的，其类型更可能是：_____(填 复制移动篡改/像素覆盖篡改/深度伪造或大模型生成篡改 的其中一个)\n"
    answerformat+="③如果是篡改或伪造的，其篡改或伪造程度是：_____(填 轻微/中等/严重 的其中一个)\n"
    answerformat+="④如果是篡改或伪造的，其篡改或伪造的位置是：_____(填图像中的某一个位置，可以是相对图像的上下左右方位，也可以是图像的内容)\n"
    answerformat+="⑤篡改伪造置信度得分：{textinfo}"
    raw+=answerformat

    answer = ""
    question = checklen(getText("user", "combined_image.jpg", raw))

    main(appid, api_key, api_secret, imageunderstanding_url, question)
    # print(answer)
